package cvfs;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.vfs2.*;
import org.apache.commons.vfs2.provider.ftp.FtpFileSystemConfigBuilder;
import org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.Date;

/**
 * @Author
 * @Date 2021-10-24 14:33
 */
public class MyVfsTest {
    private static final Logger logger = LoggerFactory.getLogger(MyVfsTest.class);
    private static FileSystemManager fsMng = null;

    /**
     * 初始化vfs
     * @return
     * @throws FileSystemException
     */
    public synchronized FileSystemManager vfsInit() throws FileSystemException {
        logger.debug("vfs使用,初始化信息...");
        if (fsMng == null) {
            try {
                FTPSetting();
                SFTPSetting();
                fsMng = VFS.getManager();
            } catch (FileSystemException ex) {
                logger.debug("vfs使用,初始化信息...失败",ex);
                throw new FileSystemException(ex);
            }
        }
        return fsMng;
    }

    private static FileSystemOptions FTPSetting(){
        FtpFileSystemConfigBuilder builder = FtpFileSystemConfigBuilder.getInstance();
        FileSystemOptions options = new FileSystemOptions();
        //解决中文乱码
        builder.setControlEncoding(options, "UTF-8");
        builder.setServerLanguageCode(options, "zh");
        return options;
    }

    private static FileSystemOptions SFTPSetting() throws FileSystemException {
        FileSystemOptions options = new FileSystemOptions();
        SftpFileSystemConfigBuilder sftpBuilder = SftpFileSystemConfigBuilder.getInstance();
        // 设false时，URI要传绝对路径,设true时，URI传相对于远程用户根目录的相对路径
        sftpBuilder.setUserDirIsRoot(options, true);
        sftpBuilder.setStrictHostKeyChecking(options, "no");
//        sftpBuilder.setTimeout(options, 10000);
        return options;
    }

    public static void delete(String path) {
        try {
            FileObject fo = fsMng.resolveFile(path);
            fo.delete();
        } catch (FileSystemException e) {
            e.printStackTrace();
        }
    }

    public static boolean isDirectory(String path) {
        try {
            FileObject fo = fsMng.resolveFile(path);
            return fo.getType().equals(FileType.FOLDER);
        } catch (FileSystemException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 获取输入流
     *
     * @param url
     * @return 文件输入流
     * @throws IOException
     */
    public static InputStream getFileToInputStream(String url) throws IOException{
        try {
            FileObject fo = fsMng.resolveFile(url);
            return fo.getContent().getInputStream();
        } catch (FileSystemException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static OutputStream getOutputStream(String path) {
        try {
            FileObject fo = fsMng.resolveFile(path);
            return fo.getContent().getOutputStream();
        } catch (FileSystemException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取字节数组
     *
     * @param url
     * @return 文件字节数组
     * @throws IOException
     */
    public static byte[] getFileToByte(String url) throws IOException{
        InputStream inputStream = getFileToInputStream(url);
        return IOUtils.toByteArray(inputStream);
    }

    /**
     * 文件上传
     * @param uploadURL
     * @param bytes
     * @return
     */
    public static boolean uploadFileToByte(String uploadURL,byte[] bytes){
        OutputStream output  =  null;
        FileObject ftpFile  = null;
        try {
            long byteLength = bytes.length;
            ftpFile = fsMng.resolveFile(uploadURL);
            if(ftpFile != null && ftpFile.exists() == false){
                ftpFile.createFile();
            }
            output = ftpFile.getContent().getOutputStream();
            IOUtils.write(bytes,output);
            if(ftpFile.isFile()){
                long size = ftpFile.getContent().getSize();
                if(byteLength == size){
                    logger.debug("文件上传成功size:{}",size);
                    return true;
                }
            }else{
                logger.debug("创建文件夹成功getURL：{}",ftpFile.getURL());
                return true;
            }
            return false;
        }catch (Exception e) {
            e.printStackTrace();
        }finally{
            if(output != null){
                try {
                    output.close();
                    output.flush();
                    ftpFile.close();
                } catch (Exception var2) {
                    var2.printStackTrace();
                }
            }
        }
        return false;
    }

    public static boolean isFile(String path) {
        try {
            FileObject fo = fsMng.resolveFile(path);
            return fo.getType().equals(FileType.FILE);
        } catch (FileSystemException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 函数描述：根据传入的文件路径创建文件夹(包括各级父文件夹)。如果路径中有文件，会自动去掉文件名。 （文件的判断是
     * 以最后一个"/"之后是否有"."为标识的，）
     *
     * @param path
     * @return 如果创建成功，返回true；否则，返回false;
     */
    public static boolean mkdirs(String path) {
        String realPath = "";
        path = path.replaceAll("\\\\", "/");
        // 如果该路径已"/"结尾，则整个字符串都是路径
        if (path.endsWith("/")) {
            realPath = path;
        } else {
            int fileNamePoint = path.lastIndexOf("/");
            // 获取真正的路径
            if (fileNamePoint >= 0) {
                realPath = path.substring(0, fileNamePoint);
            }
            // 读取文件名
            String fileName = path.substring(fileNamePoint + 1);
            // 如果读取的文件名中没有"."，说明整个字符串都是路径
            if (fileName.indexOf(".") < 0) {
                realPath = path;
            }
        }
        try {
            FileObject fo = fsMng.resolveFile(realPath);
            fo.createFolder();
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 函数描述：对文件进行copy
     *
     * @param sourceFilePath 源文件的全部路径+文件名
     * @param targetFilePath 目标文件的全部路径+文件名
     * @param overWrite      如果目标文件存在，是否覆盖。true:覆盖；false:不覆盖(当源文件和目标文件都存在并且不覆盖时,返回true)。
     * @return true:成功；false:失败; (当源文件和目标文件都存在并且不覆盖时,返回true)。
     */
    public static boolean copyFile(String sourceFilePath, String targetFilePath, boolean overWrite) throws IOException {
        if (StringUtils.isBlank(sourceFilePath) || StringUtils.isBlank(targetFilePath)) {
            throw new IOException("源文件或者目标文件为空");
        }
        FileObject from = fsMng.resolveFile(sourceFilePath);
        FileObject to = fsMng.resolveFile(targetFilePath);
        if (to.exists()) {
            if (to.getType() == FileType.FILE) {
                if (overWrite && !to.delete()) {
                    throw new IOException("目标文件[" + targetFilePath + "]被保护，不能被覆盖！");
                } else if (!overWrite) {
                    throw new IOException("目标文件[" + targetFilePath + "]已经存在！");
                }
            }
        }
        to.copyFrom(from, Selectors.SELECT_ALL);
        return true;
    }

    /**
     * Moving a File to Another File ,没有进行磁盘空间大小的判断
     *
     * @param srcFile    源文件 eg: c:\windows\abc.txt
     * @param targetFile 目标文件 eg: c:\temp\abc.txt
     * @param overWrite  如果目标文件存在，是否覆盖
     * @return success
     */
    public static boolean moveFile(String srcFile, String targetFile, boolean overWrite) throws IOException {
        if (srcFile.equals(targetFile)) {
            return true;
        }
        FileObject src = fsMng.resolveFile(srcFile);
        // File (or directory) to be moved
        if (StringUtils.isNotBlank(srcFile) && !src.exists()) {
            throw new IOException("源文件[" + srcFile + "]不存在");
        }
        // Destination directory
        FileObject to = fsMng.resolveFile(targetFile);
        if (to.exists()) {
            if (to.getType() == FileType.FILE) {
                if (overWrite && !to.delete()) {
                    throw new IOException("目标文件[" + targetFile + "]被保护，不能被覆盖！");
                } else if (!overWrite) {
                    throw new IOException("目标文件[" + targetFile + "]已经存在！");
                }
            }
        }
        src.moveTo(to);
        return true;
    }

    public static void print(String path) {
        print(path,null);
    }

    public static void print(String path,  String printPath) {
        try {
            FileSystemManager fsManager = VFS.getManager();
            FileSystemOptions opts = new FileSystemOptions();
            if (path.startsWith("sftp:")) {
                FTPSetting();
            }
            FileObject fileObject = fsManager.resolveFile(path, opts);
            if (fileObject.isFolder()) {
                FileObject[] childs = fileObject.getChildren();
                for (FileObject child : childs) {
                    print(child,printPath);
                }
            } else {
                print(fileObject,printPath);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void print(FileObject fileObject, String printPath) throws Exception {
        if (printPath != null){
            System.setOut(new PrintStream(printPath));
        }
        System.out.println("\n----------");
        System.out.println("url：" + fileObject.getPublicURIString());
        System.out.println("ModifiedTime：" + new Date(fileObject.getContent().getLastModifiedTime()));
        System.out.println("---------- content ----------");
        System.out.println(IOUtils.toString(fileObject.getContent().getInputStream(), "UTF-8"));
    }

    @Before
    public void init() throws FileSystemException {
        vfsInit();
    }

    @After
    public void after(){
        fsMng.closeFileSystem(null);
    }

    @Test
    public void testResolve() throws IOException {
        FileObject fo = fsMng.resolveFile("D:\\tem2\\test\\temp2.txt");
        FileObject foFolder = fsMng.resolveFile("D:\\tem2\\test");

        /**
         * 获取属性
         * 结果：
         * org.apache.commons.vfs2.provider.local.LocalFileSystem@4f970963
         * parent：file:///D:/tem2/test
         * name：file:///D:/tem2/test/temp2.txt
         * path：D:\tem2\test\temp2.txt
         * pubURI：file:///D:/tem2/test/temp2.txt
         * URI：file:///D:/tem2/test/temp2.txt
         * URL：file:///D:/tem2/test/temp2.txt
         * 是否文件：true
         * 是否文件夹：false
         * 是否符号链接：false
         * 是否可执行：true
         * 是否隐藏：false
         * type：file
         */
//        System.out.println("/n----------");
//        System.out.println(fo.getFileSystem()); // LocalFileSystem
//        System.out.println("parent："+fo.getParent().toString());
//        System.out.println("name："+fo.getName());
//        System.out.println("path："+fo.getPath());
//        System.out.println("pubURI："+fo.getPublicURIString());
//        System.out.println("URI："+fo.getURI().toString());
//        System.out.println("URL："+fo.getURL());
//
//        System.out.println("是否文件：" + fo.isFile());
//        System.out.println("是否文件夹：" + fo.isFolder());
//        System.out.println("是否符号链接：" + fo.isSymbolicLink());
//        System.out.println("是否可执行：" + fo.isExecutable());
//        System.out.println("是否隐藏：" + fo.isHidden());
//        System.out.println("type："+fo.getType());

        /**
         * 读取内容
         */
        if (fo.isFile()) {
            FileContent fc = fo.getContent();
            // fc.getInputStream();
            // fc.getByteArray();
            // 获取内容 - 字符串形式
            String content = fc.getString("UTF-8");
            System.out.println(content);
        }

        /**
         * 查找文件  获取子文件
         *
         * 结果：
         * --file:///D:/tem2/test/temp2.txt
         * --file:///D:/tem2/test/test1
         * --file:///D:/tem2/test
         */
//        System.out.println("/n----------");
//        if (foFolder.isFolder()) {
//            FileObject[] files = foFolder.findFiles(Selectors.SELECT_ALL);
//            for (int i = 0; i < files.length; i++) {
//                System.out.println("--" + files[i].getName());
//            }

//            // 获取所有子文件
//            FileObject[] foArr = fo.getChildren();
//            // 获取子文件（名称为test）
//            FileObject test = fo.getChild("a.txt");
//            // 从所有后代中获取类型是文件的文件
//            FileObject[] files = fo.findFiles(Selectors.SELECT_FILES);
//        }


        /**
         * 删除文件
         */
        if (fo.isFolder()) {
            // 删除此文件和所有子文件, 返回删除的数量
            int delCount = fo.deleteAll();// 同fo.delete(Selectors.SELECT_ALL);
            // 只删除所有子文件
            int del2 = fo.delete(Selectors.EXCLUDE_SELF);
            // 只删除直接子文件和空目录
            int del3 = fo.delete(Selectors.SELECT_CHILDREN);
            // 只删除文件
            int del4 = fo.delete(Selectors.SELECT_FILES);
            // 只删除空的子目录
            int del5 = fo.delete(Selectors.SELECT_FOLDERS);
            // 删除目录本身（如果包含子文件则删除失败返回0）
            int del6 = fo.delete(Selectors.SELECT_SELF);

            // 目录不为空则删除失败返回false
            boolean suc = fo.delete();
        } else if (fo.isFile()) {
            // 删除文件本身
            boolean suc = fo.delete();
        }

        // 关闭
        fo.close();
    }

    @Test
    public void testListener() throws IOException {
        // 监听文件创建，修改或删除
        FileSystemManager fsMgr = VFS.getManager();
        String path = "D:\\tem2\\test\\a.txt";
        FileObject fo = fsMgr.toFileObject(new File(path));
        // 添加监听器
        fo.getFileSystem().addListener(fo, new MyListener());
        if (!fo.exists()) {
            fo.createFile();
        }
        fo.setWritable(false, false);
//        fo.delete();
        fo.close();
    }

    private class MyListener implements FileListener {
        @Override
        public void fileCreated(FileChangeEvent event) throws Exception {
            System.out.println("fileCreated："+event.getFileObject().getName());
        }
        @Override
        public void fileDeleted(FileChangeEvent event) throws Exception {
            System.out.println("fileDeleted："+event.getFileObject().getName());
        }
        @Override
        public void fileChanged(FileChangeEvent event) throws Exception {
            System.out.println("fileChanged："+event.getFileObject().getName());
        }
    }

    @Test
    public void testDownForByte(){
        try {
            // 读取
            System.out.println("----------");
//            String url = "file:///D:/tem2/temp.txt";
//			  String url = "zip://file:///D:/tem2/晚安玫瑰.rar!/原始风景.txt";
            String url = "sftp://root:root@192.168.43.128:22/temp/temp.txt";
            byte[] bytes = getFileToByte(url);
            System.out.println("读取：" + url);
            System.out.println("读取到长度：" + bytes.length);
            System.out.println("读取到内容：" + new String(bytes));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void test(){
        try {
            // 写入
            System.out.println("----------");
            String pathUrl = "sftp://root:root@192.168.43.128/temp/temp2.txt";
            System.out.println("写入：" + pathUrl);
            boolean result = uploadFileToByte(pathUrl, "hello temp2 > java:xiaoai".getBytes());
            System.out.println("result:" + (result ? "writer success!" : "writer failed!"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testMethod() throws IOException {
//		  copyFile("D:/tem2/java.jpeg","D:/tem2/javaCope.jpeg",true);
//        moveFile("D:/tem2/javaCope.jpeg","D:/tem2/javaCopeMove.jpeg",true);
//        print("D:\\tem2\\test");
//        print("https://www.baidu.com/index.html");
        print("https://www.baidu.com/index.html","D:\\tem2\\test\\temp2.txt");
    }
}
